package org.infodavid.common.impl.services.security;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import org.infodavid.common.model.IUser;
import org.infodavid.common.services.IPasswordPolicy;
import org.infodavid.common.services.exceptions.ServiceException;
import org.infodavid.common.text.TextUtil;

/**
 * The Class DefaultPasswordPolicy.
 */
public class DefaultPasswordPolicy implements IPasswordPolicy {

	/** The min length. */
	private final byte minLength;

	/** The max length. */
	private final byte maxLength;

	/**
	 * The Constructor.
	 */
	public DefaultPasswordPolicy() {
		super();

		minLength = 0;
		maxLength = 0;
	}

	/**
	 * The Constructor.
	 * @param min the min
	 * @param max the max
	 */
	public DefaultPasswordPolicy(final int min, final int max) {
		super();

		maxLength = (byte)(max <= 0 ? 0 : max);
		minLength = (byte)(min < max ? (min <= 0 ? 0 : min) : max);
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.services.IPasswordPolicy#validate(long, java.lang.String)
	 */
	public void validate(final long userkey, final String password) throws ServiceException {
		if (password == null || password.length() == 0) {
			throw new IllegalArgumentException(IUser.PASSWORD);
		}

		final int length = password.trim().length();

		if (minLength > 0) {
			if (length < minLength) {
				throw new IllegalArgumentException(IUser.PASSWORD + ':' + password);
			}
		}

		if (maxLength > 0) {
			if (length > maxLength) {
				throw new IllegalArgumentException(IUser.PASSWORD + ':' + password);
			}
		}

		final char[] allowedCharacters = PASSWORD_CHARACTERS.toCharArray();

		Arrays.sort(allowedCharacters);

		for (final char c : password.toCharArray()) {
			if (Arrays.binarySearch(allowedCharacters, c) < 0) {
				throw new IllegalArgumentException(IUser.PASSWORD + ':' + c);
			}
		}
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.services.IPasswordPolicy#generatePassword()
	 */
	public String generatePassword() throws ServiceException {
		return TextUtil.generateRandomString(PASSWORD_CHARACTERS, PASSWORD_MIN_LENGTH);
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.services.IPasswordPolicy#encryptPassword(java.lang.String)
	 */
	public String encryptPassword(final String value) throws ServiceException {
		MessageDigest algorithm;
		BigInteger number;

		try {
			algorithm = MessageDigest.getInstance("MD5");
			number = new BigInteger(1, algorithm.digest(value.getBytes()));

			return number.toString(16);
		}
		catch (final NoSuchAlgorithmException e) {
			throw new ServiceException(e);
		}
	}
}
